package com.sikaryofficial.backend.service.store;

import com.sikaryofficial.backend.constant.RedisCacheKey;
import com.sikaryofficial.backend.domain.vo.store.StoreMetricVO;
import com.sikaryofficial.backend.mapper.StoreMapper;
import com.sikaryofficial.backend.utils.MinMaxNormalizer;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.redis.lock.RedisDistributedLocker;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.sikaryofficial.backend.constant.RedisCacheKey.ACTIVITY_WINNER_EXPORT_LOCK;

/**
 * @author : qinjinyuan
 * @desc :  店铺推荐服务
 * @date : 2025/08/22 17:10
 */
@Service
@Slf4j
public class RecommendService {
    @Autowired
    protected RedisDistributedLocker locker;
    @Autowired
    private StoreMapper storeMapper;
    @Autowired
    private RedisService redisService;

    @Async("asyncTaskExecutor")
    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
    public void calculateRecommendScores() {
        log.info("开始执行推荐算法计算...");
        // 设置锁key
        String lockKey = RedisCacheKey.STORE_RECOMMEND_Z_SET_LOCK;
        if (locker.tryLock(lockKey, TimeUnit.MINUTES, 1, 1)) {
            try {
                processData();
            } catch (Exception e) {
                log.error("Redeem fail: {}", e);
            } finally {
                locker.unlock(lockKey);
            }
        } else {
            log.error("Get lock fail");
        }
    }

    private void processData() {
        // 1. 获取所有店铺指标
        List<StoreMetricVO> metrics = storeMapper.getRecommendMetrics();
        if (metrics.isEmpty()) {
            return;
        }

        // 2. Min-Max 标准化
        MinMaxNormalizer.normalize(metrics, m -> (double) m.getSearchCount(), StoreMetricVO::setSearchNorm);
        MinMaxNormalizer.normalize(metrics, m -> (double) m.getViewCount(), StoreMetricVO::setViewNorm);
        MinMaxNormalizer.normalize(metrics, m -> (double) m.getCommentCount(), StoreMetricVO::setCommentNorm);
        MinMaxNormalizer.normalize(metrics, StoreMetricVO::getAvgRating, StoreMetricVO::setRatingNorm);

        // 3. 写入 Redis ZSet
        String cacheKey = RedisCacheKey.STORE_RECOMMEND_Z_SET_KEY;

        redisService.removeRangeCacheZSet(cacheKey, 0, -1); // 清空旧数据
        for (StoreMetricVO m : metrics) {
            double behaviorScore =
                    m.getSearchNorm() * 0.4 +
                            m.getViewNorm() * 0.3 +
                            m.getCommentNorm() * 0.2 +
                            m.getRatingNorm() * 0.1;

            double matchScore =
                    m.getNearbyTagMatch() * 0.6 +
                            m.getShopTypeMatch() * 0.4;

            double totalScore = behaviorScore + matchScore;

            redisService.setCacheZSet(cacheKey, m.getStoreId().toString(), totalScore);
        }
        log.info("推荐算法计算完成，共处理 {} 个店铺，结果已写入 Redis", metrics.size());
    }
}
